
import os
from random import randint
import numpy as np
import matplotlib.pyplot as plt


class Parameter:
    per = 1
    locRng = [0, 100] #100*100的二维空间
    TList = [500, 1000, 2500, 5000, 10000]
#     WList = [100, 200, 500, 1000, 5000]
    WList = [500, 1000, 2500, 5000, 10000]
    cwList = [1, 2, 3, 4, 5]#工作者能力
    rwList = [1.0, 1.5, 2.0, 2.5, 3.0]#工作者的半径
    dwList = [0.1, 0.3, 0.5, 0.7, 0.9]#工作者的接受率
    ddlList = [2, 4, 6, 8, 10]#截止时间
    # ptList = [2, 5, 10, 20, 15,50]
    ptList = [2, 5, 10, 15, 20]#任务报酬
    lambdaList = [2, 5, 10, 20, 50]#指数分布的参数
    muList = [2, 5, 10, 20, 50]#正太分布的参数
    defaultValues = {
        "T": TList[int(len(TList)/2)],
        "W": WList[int(len(WList)/2)],
        "cw": cwList[int(len(cwList)/6)],
        "rw": rwList[int(len(rwList)/2)],
        "dw": dwList[int(len(dwList)/2)],
        "ddl": ddlList[int(len(ddlList)/2)],
        "pt": ptList[int(len(ptList)/2)],
        "lambda": lambdaList[int(len(lambdaList)/2)],
        "muList": muList[int(len(muList)/2)],
    }
    umax = max(dwList)*max(ptList)
    umin = min(dwList)*min(ptList)



#正态分布
class normalGenerator:

    def __init__(self, mu, sigma):
        self.mu = mu #mu是正态分布的中心线左右移动
        self.sigma = sigma#sigma是正态分布宽窄的参数

    def gen(self, n, lb = None, rb = None):#指定范围lb-rb
        ret = np.random.normal(self.mu, self.sigma, n)
        for i in range(n):#检查超出范围的数据
            if lb is not None and ret[i]<lb:
                ret[i] = lb
            if rb is not None and ret[i]>rb:
                ret[i] = rb
        return ret
#均匀分布
class uniformGenerator:

    def __init__(self, low, high):
        self.low = low
        self.high = high

    def gen(self, n, lb = None, rb = None):
        ret = np.random.uniform(self.low, self.high, n)
        for i in range(n):
            if lb is not None and ret[i]<lb:
                ret[i] = lb
            if rb is not None and ret[i]>rb:
                ret[i] = rb
        return ret
#指数分布
class expGenerator:

    def __init__(self, mu):
        self.mu = mu

    def gen(self, n, lb = None, rb = None):
        ret = np.random.exponential(self.mu, n)
        for i in range(n):
            if lb is not None and ret[i]<lb:
                ret[i] = lb
            if rb is not None and ret[i]>rb:
                ret[i] = rb
        return ret

       

#功能是生成工作者位置信息，n 是生成的工作者数量，low指定坐标最小数值，high坐标最大值
def genWorkers(n:int,low:int,high:int)->list:
    ret = []
    st = set()
    maxRadius = max(Parameter.rwList)
    x_center=y_center=(low+high)/2
    x_value = []
    y_value = []
    for i in range(n):
        while True:
            deta_x = 1.0*randint(low*10**6, high*10**6) / 10**6
            deta_y = 1.0*randint(low*10**6, high*10**6) / 10**6
            radius = deta_x**2 + deta_y**2
            x = x_center + deta_x
            y = y_center + deta_y
            t = (x, y)
            if t not in st and radius < maxRadius:
                break
        ret.append(t)
        st.add(t)
        x_value.append(t[0])
        y_value.append(t[1])
    import matplotlib.pyplot as plt
    plt.scatter(x_value,y_value)
    plt.show()
    return ret

#功能是生成任务位置,workerLoc工作者的位置，rw是工作者的活动范围,tPerw每一个工作者对应几个能匹配的任务
def genTasks(workerLoc:list,rw:int,tPerw:int)->list:
    n = len(workerLoc)
    tlocs = []
    st = [] #标记是否生成
    for i in range(n):
        wloc_x = workerLoc[i][0]
        wloc_y = workerLoc[i][1]
        for j in range(tPerw):
            while True:#我们在以圆心为中心，以二倍半径为边长的正方形内部进行随机选点，当点落在圆内或者圆上时，满足条件则加入。
                deta_tloc_x = 1.0*randint(0,(2*rw)*10**6)/10**6
                deta_tloc_y = 1.0*randint(0,(2*rw)*10**6)/10**6
                radius = deta_tloc_x**2+deta_tloc_y**2
                tloc_x = deta_tloc_x + wloc_x
                tloc_y = deta_tloc_y + wloc_y
                tloc = (tloc_x, tloc_y)
                if radius <= rw**2 and tloc not in st:
#                     print(math.sqrt(radius))
                    break
            st.append(tloc)
            tlocs.append(tloc)
    return tlocs

#报酬正太分布
def genPtsNormal(n,mu,sigma=3.75):
    generator = normalGenerator(mu,sigma)
    lb = 0.01
    rb = Parameter.umax
    pts = generator.gen(n,lb,rb)
    pts = pts.tolist()
    return pts

#均匀分布
def genPtsUniform(n,pt):
    low = 0
    high = max(Parameter.ptList)
    generator = uniformGenerator(low,high)
    lb = 0.01
    rb = Parameter.umax
    pts = generator.gen(n,lb,rb)
    pts = pts.tolist()
    return pts
    
#报酬指数分布
def genPtsExponential(n,mu):
    generator = expGenerator(mu)
    lb = 0.01
    rb = Parameter.umax
    pts = generator.gen(n,lb,rb)
    pts = pts.tolist()
    return pts
    
    
#工作者接受率正太分布
def genDws(n, mu,sigma=0.05):#n生成的数量，mu所有样本的平均值，sigma 样本范围
    dwsGenerator = normalGenerator(mu,sigma)
    lb = 0.01
    rb = 1.0
    data = dwsGenerator.gen(n,lb,rb)
    data = data.tolist()
    return data

#工作者能力正太分布
def genCws(n, mu, sigma, lb, rb)->list:#n 生成的数量，mu是平均值，sigma 是样本范围，lb生成数据下界，rb生成数据的上届
#     data = np.round(np.random.normal(mu,sigma,n)).astype(int)
#     for i in range(n):
#         if data[i] < lb:
#             data[i] = lb
#         if data[i] > rb:
#             data[i] = rb
    cwsGenerator = normalGenerator(mu,sigma)
    data = cwsGenerator.gen(n,lb,rb)
    data = [int(np.round(num)) for num in data]
    return data

#工作者活动半径
def genRws(n,mu,sigma,lb,rb):
    rwsGenerator = normalGenerator(mu,sigma)
    data = rwsGenerator.gen(n,lb,rb)
    data = data.tolist()
    return data

#生成截止时间
def genDdls(n,mu,sigma,lb,rb):
    ddlsGenerator = normalGenerator(mu,sigma)
    data = ddlsGenerator.gen(n,lb,rb)
    data = [int(np.round(num)) for num in data]
    return data

#根据工作者数量随机抽样一个工作者
def sampleWorkerLoc(arrtime:int,wlocs:list,rws:list,cws:list,wddls:list,dws:list):
    ret = [arrtime,'w']
    
    windex = randint(0,len(wlocs)-1)
    windex = 0
    for i in wlocs[windex]:
        ret.append(i)
    wlocs.pop(windex)
    
#     rwindex = randint(0,len(rws)-1)
    rwindex = 0
    ret.append(rws[rwindex])
    rws.pop(rwindex)
    
#     cwindex = randint(0,len(cws)-1)
    cwindex = 0
    ret.append(cws[cwindex])
    cws.pop(cwindex)
    
#     wddlindex = randint(0,len(wddls)-1)
    wddlindex = 0
    ret.append(wddls[wddlindex])
    wddls.pop(wddlindex)
    
#     dwindex = randint(0,len(dws)-1)    
    dwindex = 0
    ret.append(dws[dwindex])
    dws.pop(dwindex)
    return ret

#任务抽样
def sampleTask(arrtime:int,tlocs:list,tddls:list,pts:list):
    ret = [arrtime,'t']
    
    tindex = randint(0,len(tlocs)-1)
    tindex = 0
    for i in tlocs[tindex]:
        ret.append(i)
    tlocs.pop(tindex)
    
#     tddlindex = randint(0,len(tddls)-1)
    tddlindex = 0
    ret.append(tddls[tddlindex])
    tddls.pop(tddlindex)
    
#     ptindex = randint(0,len(pts)-1)    
    ptindex = 0
    ret.append(pts[ptindex])
    pts.pop(ptindex)
    
    return ret

#把数据写入文件
def writeData(desFilePath,wnum,tnum,data):
    if os.path.isdir(desFilePath):
        pass
    else:
        os.mkdir(desFilePath)
    fileName = desFilePath+"/"+str(wnum)+"_"+str(tnum)+".txt"
    print(fileName)
    with open(fileName,"w") as f:
        for items in data:
            outstr = ""
            for item in items:
                outstr+=str(item)+" "
            outstr += "\n"
            f.write(outstr)
        
    

def scalability(desFilePath):
    umax = Parameter.umax
    wmax = 10*(10**2)
    tmax = wmax*Parameter.per
    cw = Parameter.defaultValues["cw"]
    rw = Parameter.defaultValues["rw"]
    dw = Parameter.defaultValues["dw"]
    ddl = Parameter.defaultValues["ddl"]
    pt = Parameter.defaultValues["pt"]
    wlocs  = genWorkers(wmax,Parameter.locRng[0],Parameter.locRng[1])
    tlocs = genTasks(wlocs, rw, Parameter.per)
    cws = genCws(wmax,cw,0,cw,cw)
    rws = genRws(wmax,rw,rw,0,rw*2)
    dws = genDws(wmax, dw, 0.3)
    dws = sorted(dws)
    wddls = genDdls(wmax,ddl,0,ddl,ddl)
    tddls = genDdls(tmax,ddl,0,ddl,ddl)
    pts = genPtsNormal(tmax, pt,3.75)
    pts = sorted(pts)    
    
    umax = int(round(max(dws)*max(pts)))
    first = [wmax,tmax,umax,wmax+tmax]
    data = []
    data.append(first)
    arr = 0
    while True:
        if(len(wlocs)==0 and len(tlocs)==0):#说明生成完毕
            break
        form = randint(0,1)#随机选择工作者还是任务到达
#         form = arr%2#随机选择工作者还是任务到达
        if form == 0 and len(wlocs)>0:#工作者到达
            data.append(sampleWorkerLoc(arr,wlocs,rws,cws,wddls,dws))
        if form == 1 and len(tlocs)>0:#任务到达
            data.append(sampleTask(arr,tlocs,tddls,pts))
        arr += 1
        
    print(len(data))
    writeData(desFilePath,wmax,tmax,data)

desFilePath = "./synthetic"
scalability(desFilePath)
            

mu = 3
sigma = 1
pt = 50
minGenerator = normalGenerator(mu,sigma)
data = minGenerator.gen(100, 1, 5)
minGenerator = uniformGenerator(0,pt*1.5)
data = minGenerator.gen(100,pt*0.1,100)
# minGenerator = expGenerator(mu)
# data = minGenerator.gen(100,pt*0.1,100)

# data = np.random.normal(mu,sigma,100)
# data = np.round(np.random.normal(50,1,size=100)).astype(int)
# data = genCws(100,50,0,0,100)
# print(data)
# plt.hist(data, bins=20, density=True)
# plt.show()